package com.lagou.filter;

import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Activate(group = {CommonConstants.CONSUMER})
public class TPMonitorFilter implements Filter {

    private static ConcurrentHashMap<String, List<Temp>> tpMap = new ConcurrentHashMap<>();

    private static final ScheduledExecutorService REPORT_WORKER = Executors.newScheduledThreadPool(1);
    private static final long LOOK_TIME = 60*1000L;
    private static final long DELAY = 5L;
    private static int x = 1;
    private static String[] methodName = {"sayHello","sayHello2","sayHello3"};
    static {
        System.out.println("进来了");
        //5s输出一次各个方法的TP90,TP99的耗时情况
        REPORT_WORKER.scheduleWithFixedDelay(() -> {
            System.out.println("执行了"+(x++)+"次");
            for (String s : methodName) {
                List<Temp> time = tpMap.get(s);
                if (CollectionUtils.isEmpty(time)){
                    System.out.println("方法"+s+"没有被调用");
                    continue;
                }
                if (CollectionUtils.isEmpty(time)){
                    System.out.println("方法"+s+"一分钟内没有被调用");
                    continue;
                }
                time = time.stream().sorted(((o1, o2) -> (int) (o1.getConsumingTime()-o2.getConsumingTime()))).collect(Collectors.toList());
                int i = Math.max(time.size() * 90 / 100 - 1, 0);
                int i2 = Math.max(time.size() * 99 / 100 - 1, 0);

                System.out.println("方法"+s+": 最近一分钟调用次数："+time.size()+" TP90: "+time.get(i).getConsumingTime()+" TP99: "+time.get(i2).getConsumingTime());

            }
        }, DELAY, DELAY, TimeUnit.SECONDS);
    }
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long   startTime  = System.currentTimeMillis();
        try {
            // 执行方法
            return  invoker.invoke(invocation);
        } finally {
            long l = System.currentTimeMillis() - startTime;
//            System.out.println("方法"+invocation.getMethodName()+"invoke time:"+ l + "毫秒");
            List<Temp> maps =
                    Optional.ofNullable(tpMap.get(invocation.getMethodName())).orElse(new ArrayList<Temp>());
            maps.removeIf(o -> startTime-o.getTime()>LOOK_TIME);
            maps.add(new Temp(startTime, l));
            tpMap.put(invocation.getMethodName(),maps);
        }

    }

    class Temp {
        private Long time;
        private Long consumingTime;

        public Temp(Long time, Long consumingTime) {
            this.time = time;
            this.consumingTime = consumingTime;
        }

        public Long getTime() {
            return time;
        }

        public void setTime(Long time) {
            this.time = time;
        }

        public Long getConsumingTime() {
            return consumingTime;
        }

        public void setConsumingTime(Long consumingTime) {
            this.consumingTime = consumingTime;
        }

    }
}
